package jxd.myDwr;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import org.directwebremoting.Container;
import org.directwebremoting.impl.AbstractContainer;
import org.directwebremoting.util.LocalUtil;
import org.directwebremoting.util.Logger;

public class DefaultContainer extends AbstractContainer
  implements Container,Serializable 
{
  protected Map beans = new TreeMap();

  private static final Logger log = Logger.getLogger(DefaultContainer.class);

  public void addParameter(Object askFor, Object valueParam)
    throws InstantiationException, IllegalAccessException
  {
    Object value = valueParam;

    if ((value instanceof String))
    {
      try
      {
        Class impl = LocalUtil.classForName((String)value);
        value = impl.newInstance();
      }
      catch (ClassNotFoundException ex)
      {
      }

    }

    if ((!(value instanceof String)) && ((askFor instanceof String)))
    {
      try
      {
        Class iface = LocalUtil.classForName((String)askFor);
        if (!iface.isAssignableFrom(value.getClass()))
        {
          log.error("Can't cast: " + value + " to " + askFor);
        }
      }
      catch (ClassNotFoundException ex)
      {
      }

    }

    if (log.isDebugEnabled())
    {
      if ((value instanceof String))
      {
        log.debug("Adding IoC setting: " + askFor + "=" + value);
      }
      else
      {
        log.debug("Adding IoC implementation: " + askFor + "=" + value.getClass().getName());
      }
    }

    this.beans.put(askFor, value);
  }

  public void setupFinished()
  {
    for (Iterator it = this.beans.entrySet().iterator(); it.hasNext(); )
    {
      Map.Entry entry = (Map.Entry)it.next();

      Object ovalue = entry.getValue();

      if (!(ovalue instanceof String))
      {
        log.debug("Trying to autowire: " + ovalue.getClass().getName());

        Method[] methods = ovalue.getClass().getMethods();

        for (int i = 0; i < methods.length; i++)
        {
          Method setter = methods[i];

          if ((!setter.getName().startsWith("set")) || (setter.getName().length() <= 3) || (setter.getParameterTypes().length != 1))
          {
            continue;
          }
          String name = Character.toLowerCase(setter.getName().charAt(3)) + setter.getName().substring(4);
          Class propertyType = setter.getParameterTypes()[0];

          Object setting = this.beans.get(name);
          if (setting != null)
          {
            if (propertyType.isAssignableFrom(setting.getClass()))
            {
              log.debug("- autowire-by-name: " + name + "=" + setting);
              invoke(setter, ovalue, setting);

              continue;
            }
            if (setting.getClass() == String.class)
            {
              try
              {
                Object value = LocalUtil.simpleConvert((String)setting, propertyType);

                log.debug("- autowire-by-name: " + name + "=" + value);
                invoke(setter, ovalue, value);
              }
              catch (IllegalArgumentException ex)
              {
              }

            }

          }

          Object value = this.beans.get(propertyType.getName());
          if (value != null)
          {
            log.debug("- autowire-by-type: " + name + "=" + value.getClass().getName());
            invoke(setter, ovalue, value);
          }
          else
          {
            log.debug("- skipped autowire: " + name);
          }
        }
      }
    }

    callInitializingBeans();
  }

  private static void invoke(Method setter, Object bean, Object value)
  {
    try
    {
      setter.invoke(bean, new Object[] { value });
    }
    catch (IllegalArgumentException ex)
    {
      log.error("- Internal error: " + ex.getMessage());
    }
    catch (IllegalAccessException ex)
    {
      log.error("- Permission error: " + ex.getMessage());
    }
    catch (InvocationTargetException ex)
    {
      log.error("- Exception during auto-wire: ", ex.getTargetException());
    }
  }

  public Object getBean(String id)
  {
    Object reply = this.beans.get(id);
    if (reply == null)
    {
      log.debug("DefaultContainer: No bean with id=" + id);
    }

    return reply;
  }

  public Collection getBeanNames()
  {
    return Collections.unmodifiableCollection(this.beans.keySet());
  }
}